From 9b7c36c3266e74ee91d484e99bbf7af35727eec9 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Thu, 17 Jun 2004 14:48:17 +0000 Subject: [PATCH] bitkeeper revision 1.974.1.1 (40d1af31iUa7xgOjIcSvMJwh-WxR2g) Cleanups. --- xen/arch/x86/i8259.c | 102 ++----- xen/arch/x86/irq.c | 541 +++++++----------------------------- xen/arch/x86/pci-irq.c | 4 +- xen/arch/x86/setup.c | 4 +- xen/arch/x86/time.c | 7 +- xen/drivers/char/keyboard.c | 19 +- xen/drivers/char/serial.c | 22 +- xen/include/asm-x86/irq.h | 16 +- xen/include/xen/interrupt.h | 3 - xen/include/xen/irq.h | 6 +- xen/include/xen/sched.h | 6 - 11 files changed, 156 insertions(+), 574 deletions(-) diff --git a/xen/arch/x86/i8259.c b/xen/arch/x86/i8259.c index 58ecb12553..42d8ab2028 100644 --- a/xen/arch/x86/i8259.c +++ b/xen/arch/x86/i8259.c @@ -48,7 +48,7 @@ BUILD_COMMON_IRQ() * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: * (these are usually mapped to vectors 0x30-0x3f) */ - BUILD_16_IRQS(0x0) +BUILD_16_IRQS(0x0) #ifdef CONFIG_X86_IO_APIC /* @@ -61,10 +61,10 @@ BUILD_COMMON_IRQ() * * (these are usually mapped into the 0x30-0xff vector range) */ - BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) - BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) - BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) - BUILD_16_IRQS(0xc) +BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) +BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) +BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) +BUILD_16_IRQS(0xc) #endif #undef BUILD_16_IRQS @@ -77,23 +77,21 @@ BUILD_COMMON_IRQ() * through the ICC by us (IPIs) */ #ifdef CONFIG_SMP - BUILD_SMP_INTERRUPT(event_check_interrupt,EVENT_CHECK_VECTOR) - BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) - BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +BUILD_SMP_INTERRUPT(event_check_interrupt,EVENT_CHECK_VECTOR) +BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) #endif /* - * every pentium local APIC has two 'local interrupts', with a + * Every pentium local APIC has two 'local interrupts', with a * soft-definable vector attached to both interrupts, one of * which is a timer interrupt, the other one is error counter * overflow. Linux uses the local APIC timer interrupt to get * a much simpler SMP time architecture: */ -#ifdef CONFIG_X86_LOCAL_APIC - BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) - BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) - BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) -#endif +BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) #define IRQ(x,y) \ IRQ##x##y##_interrupt @@ -374,56 +372,24 @@ void __init init_8259A(int auto_eoi) spin_unlock_irqrestore(&i8259A_lock, flags); } +static struct irqaction cascade = { no_action, "cascade", NULL}; -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ - -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; - -void __init init_ISA_irqs (void) +void __init init_IRQ(void) { int i; -#ifdef CONFIG_X86_LOCAL_APIC init_bsp_APIC(); -#endif - init_8259A(0); - for (i = 0; i < NR_IRQS; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - - if (i < 16) { - /* - * 16 old-style INTA-cycle interrupts: - */ - irq_desc[i].handler = &i8259A_irq_type; - } else { - /* - * 'high' PCI IRQs filled in on demand - */ - irq_desc[i].handler = &no_irq_type; - } - } -} - -void __init init_IRQ(void) -{ - int i; - - init_ISA_irqs(); + init_8259A(0); - /* - * Cover the whole vector space, no vector can escape - * us. (some of these will be overridden and become - * 'special' SMP interrupts) - */ - for (i = 0; i < NR_IRQS; i++) { - int vector = FIRST_EXTERNAL_VECTOR + i; - if (vector != HYPERVISOR_CALL_VECTOR) - set_intr_gate(vector, interrupt[i]); + for ( i = 0; i < NR_IRQS; i++ ) + { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = (i<16) ? &i8259A_irq_type : &no_irq_type; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + spin_lock_init(&irq_desc[i].lock); + set_intr_gate(FIRST_EXTERNAL_VECTOR+i, interrupt[i]); } #ifdef CONFIG_SMP @@ -433,38 +399,26 @@ void __init init_IRQ(void) */ set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); - /* - * The reschedule interrupt is a CPU-to-CPU reschedule-helper - * IPI, driven by wakeup. - */ + /* Various IPI functions. */ set_intr_gate(EVENT_CHECK_VECTOR, event_check_interrupt); - - /* IPI for invalidation */ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); - - /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); #endif -#ifdef CONFIG_X86_LOCAL_APIC - /* self generated IPI for local APIC timer */ + /* Self-generated IPI for local APIC timer. */ set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - /* IPI vectors for APIC spurious and error interrupts */ + /* IPI vectors for APIC spurious and error interrupts. */ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); -#endif - /* - * Set the clock to HZ Hz, we already have a valid - * vector now: - */ + /* Set the clock to HZ Hz */ #define CLOCK_TICK_RATE 1193180 /* crystal freq (Hz) */ #define LATCH (((CLOCK_TICK_RATE)+(HZ/2))/HZ) outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ - setup_irq(2, &irq2); + setup_irq(2, &cascade); } diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 068085d0db..bdb070dc63 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1,106 +1,34 @@ -/* - * linux/arch/i386/kernel/irq.c - * - * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar - * - * This file contains the code used by various IRQ handling routines: - * asking for different IRQ's should be done through these routines - * instead of just grabbing them. Thus setup_irqs with different IRQ numbers - * shouldn't result in any weird surprises, and installing new handlers - * should be easier. - */ - -/* - * (mostly architecture independent, will move to kernel/irq.c in 2.5.) - * - * IRQs are in fact implemented a bit like signal handlers for the kernel. - * Naturally it's not a 1:1 relation, but there are similarities. +/****************************************************************************** + * arch/x86/irq.c + * + * Portions of this file are: + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar */ #include -#include #include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include -/* - * Linux has a controller-independent x86 interrupt architecture. - * every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the apropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, - * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. - * (IO-APICs assumed to be messaging to Pentium local-APICs) - * - * the code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic. - */ - -/* - * Controller mappings for all interrupt sources: - */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = -{ [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned; static void __do_IRQ_guest(int irq); -/* - * Special irq handlers. - */ - void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } -/* - * Generic no controller code - */ - static void enable_none(unsigned int irq) { } static unsigned int startup_none(unsigned int irq) { return 0; } static void disable_none(unsigned int irq) { } static void ack_none(unsigned int irq) { -/* - * 'what should we do if we get a hw irq event on an illegal vector'. - * each architecture has to answer this themselves, it doesnt deserve - * a generic callback i think. - */ -#if CONFIG_X86 - printk("unexpected IRQ trap at vector %02x\n", irq); -#ifdef CONFIG_X86_LOCAL_APIC - /* - * Currently unexpected vectors happen only on SMP and APIC. - * We _must_ ack these because every local APIC has only N - * irq slots per priority level, and a 'hanging, unacked' IRQ - * holds up an irq slot - in excessive cases (when multiple - * unexpected vectors occur) that might lock up the APIC - * completely. - */ + printk("Unexpected IRQ trap at vector %02x.\n", irq); ack_APIC_irq(); -#endif -#endif } -/* startup is the same as "enable", shutdown is same as "disable" */ #define shutdown_none disable_none #define end_none enable_none @@ -115,420 +43,132 @@ struct hw_interrupt_type no_irq_type = { }; atomic_t irq_err_count; -#ifdef CONFIG_X86_IO_APIC -#ifdef APIC_MISMATCH_DEBUG atomic_t irq_mis_count; -#endif -#endif - -/* - * Generic, controller-independent functions: - */ - -/* - * This should really return information about whether - * we should do bottom half handling etc. Right now we - * end up _always_ checking the bottom half, which is a - * waste of time and is not what some drivers would - * prefer. - */ -static int handle_IRQ_event(unsigned int irq, - struct pt_regs * regs, - struct irqaction * action) -{ - int status; - int cpu = smp_processor_id(); - - irq_enter(cpu, irq); - - status = 1; /* Force the "do bottom halves" bit */ - if (!(action->flags & SA_INTERRUPT)) - __sti(); - - do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - - __cli(); - - irq_exit(cpu, irq); - - return status; -} - -/* - * Generic enable/disable code: this just calls - * down into the PIC-specific version for the actual - * hardware disable after having gotten the irq - * controller lock. - */ - -/** - * disable_irq_nosync - disable an irq without waiting - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Disables and Enables are - * nested. - * Unlike disable_irq(), this function does not ensure existing - * instances of the IRQ handler have completed before returning. - * - * This function may be called from IRQ context. - */ - inline void disable_irq_nosync(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = &irq_desc[irq]; unsigned long flags; spin_lock_irqsave(&desc->lock, flags); - if (!desc->depth++) { + + if ( desc->depth++ == 0 ) + { desc->status |= IRQ_DISABLED; desc->handler->disable(irq); } + spin_unlock_irqrestore(&desc->lock, flags); } -/** - * disable_irq - disable an irq and wait for completion - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and Disables are - * nested. - * This function waits for any pending IRQ handlers for this interrupt - * to complete before returning. If you use this function while - * holding a resource the IRQ handler may need you will deadlock. - * - * This function may be called - with care - from IRQ context. - */ - void disable_irq(unsigned int irq) { disable_irq_nosync(irq); - - if (!local_irq_count(smp_processor_id())) { - do { - barrier(); - cpu_relax(); - } while (irq_desc[irq].status & IRQ_INPROGRESS); - } + do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS ); } -/** - * enable_irq - enable handling of an irq - * @irq: Interrupt to enable - * - * Undoes the effect of one call to disable_irq(). If this - * matches the last disable, processing of interrupts on this - * IRQ line is re-enabled. - * - * This function may be called from IRQ context. - */ - void enable_irq(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; + irq_desc_t *desc = &irq_desc[irq]; unsigned long flags; spin_lock_irqsave(&desc->lock, flags); - switch (desc->depth) { - case 1: { - unsigned int status = desc->status & ~IRQ_DISABLED; - desc->status = status; - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - desc->status = status | IRQ_REPLAY; + + if ( --desc->depth == 0 ) + { + desc->status &= ~IRQ_DISABLED; + if ( (desc->status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING ) + { + desc->status |= IRQ_REPLAY; hw_resend_irq(desc->handler,irq); } desc->handler->enable(irq); - /* fall-through */ - } - default: - desc->depth--; - break; - case 0: - printk("enable_irq(%u) unbalanced from %p\n", irq, - __builtin_return_address(0)); } + spin_unlock_irqrestore(&desc->lock, flags); } -/* - * do_IRQ handles all normal device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - */ -asmlinkage unsigned int do_IRQ(struct pt_regs regs) +asmlinkage void do_IRQ(struct pt_regs regs) { - /* - * We ack quickly, we don't want the irq controller - * thinking we're snobs just because some other CPU has - * disabled global interrupts (we have already done the - * INT_ACK cycles, it's too late to try to pretend to the - * controller that we aren't taking the interrupt). - * - * 0 return value means that this irq is already being - * handled by some other CPU. (or is disabled) - */ - int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ - irq_desc_t *desc = irq_desc + irq; - struct irqaction * action; - unsigned int status; + unsigned int irq = regs.orig_eax & 0xff; + irq_desc_t *desc = &irq_desc[irq]; + struct irqaction *action; -#ifdef PERF_COUNTERS - int cpu = smp_processor_id(); - u32 cc_start, cc_end; - - perfc_incra(irqs, cpu); - rdtscl(cc_start); -#endif + perfc_incrc(irqs); spin_lock(&desc->lock); desc->handler->ack(irq); - /* - REPLAY is when Linux resends an IRQ that was dropped earlier - WAITING is used by probe to mark irqs that are being tested - */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; /* we _want_ to handle it */ - - /* We hook off guest-bound IRQs for special handling. */ - if ( status & IRQ_GUEST ) + if ( likely(desc->status & IRQ_GUEST) ) { __do_IRQ_guest(irq); spin_unlock(&desc->lock); - return 1; + return; } - /* - * If the IRQ is disabled for whatever reason, we cannot use the action we - * have. - */ - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status &= ~IRQ_PENDING; /* we commit to handling */ - status |= IRQ_INPROGRESS; /* we are handling it */ - } - desc->status = status; + desc->status &= ~IRQ_REPLAY; + desc->status |= IRQ_PENDING; /* - * If there is no IRQ handler or it was disabled, exit early. Since we set - * PENDING, if another processor is handling a different instance of this - * same irq, the other processor will take care of it. + * Since we set PENDING, if another processor is handling a different + * instance of this same irq, the other processor will take care of it. */ - if (!action) + if ( desc->status & (IRQ_DISABLED | IRQ_INPROGRESS) ) goto out; - /* - * Edge triggered interrupts need to remember pending events. This applies - * to any hw interrupts that allow a second instance of the same irq to - * arrive while we are in do_IRQ or in the handler. But the code here only - * handles the _second_ instance of the irq, not the third or fourth. So - * it is mostly useful for irq hardware that does not mask cleanly in an - * SMP environment. - */ - for (;;) { - spin_unlock(&desc->lock); - handle_IRQ_event(irq, ®s, action); - spin_lock(&desc->lock); - - if (!(desc->status & IRQ_PENDING)) - break; + desc->status |= IRQ_INPROGRESS; + + action = desc->action; + while ( desc->status & IRQ_PENDING ) + { desc->status &= ~IRQ_PENDING; + irq_enter(smp_processor_id(), irq); + spin_unlock_irq(&desc->lock); + action->handler(irq, action->dev_id, ®s); + spin_lock_irq(&desc->lock); + irq_exit(smp_processor_id(), irq); } + desc->status &= ~IRQ_INPROGRESS; + out: - /* - * The ->end() handler has to deal with interrupts which got disabled - * while the handler was running. - */ desc->handler->end(irq); spin_unlock(&desc->lock); - -#ifdef PERF_COUNTERS - rdtscl(cc_end); - - if ( !action || (!(action->flags & SA_NOPROFILE)) ) - { - perfc_adda(irq_time, cpu, cc_end - cc_start); -#ifndef NDEBUG - if ( (cc_end - cc_start) > (cpu_khz * 100) ) - printk("Long interrupt %08x -> %08x\n", cc_start, cc_end); -#endif - } -#endif - - return 1; } -/** - * request_irq - allocate an interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt line and IRQ handling. From the point this - * call is made your handler function may be invoked. Since - * your handler function must clear any interrupt the board - * raises, you must take care both to initialise your hardware - * and to set up the interrupt handler in the right order. - * - * Dev_id must be globally unique. Normally the address of the - * device data structure is used as the cookie. Since the handler - * receives this value it makes sense to use it. - * - * If your interrupt is shared you must pass a non NULL dev_id - * as this is required when freeing the interrupt. - * - * Flags: - * - * SA_SHIRQ Interrupt is shared - * - * SA_INTERRUPT Disable local interrupts while processing - */ - -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) +void free_irq(unsigned int irq) { - int retval; - struct irqaction * action; - - if (irq >= NR_IRQS) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = setup_irq(irq, action); - if (retval) - kfree(action); - - return retval; -} - -/** - * free_irq - free an interrupt - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Remove an interrupt handler. The handler is removed and if the - * interrupt line is no longer in use by any driver it is disabled. - * On a shared IRQ the caller must ensure the interrupt is disabled - * on the card it drives before calling this function. The function - * does not return until any executing interrupts for this IRQ - * have completed. - * - * This function may be called from interrupt context. - * - * Bugs: Attempting to free an irq in a handler for the same irq hangs - * the machine. - */ - -void free_irq(unsigned int irq, void *dev_id) -{ - irq_desc_t *desc; - struct irqaction **p; + irq_desc_t *desc = &irq_desc[irq]; unsigned long flags; - if (irq >= NR_IRQS) - return; - - desc = irq_desc + irq; spin_lock_irqsave(&desc->lock,flags); - p = &desc->action; - for (;;) { - struct irqaction * action = *p; - if (action) { - struct irqaction **pp = p; - p = &action->next; - if (action->dev_id != dev_id) - continue; - - /* Found it - now remove it from the list of entries */ - *pp = action->next; - if (!desc->action) { - desc->status |= IRQ_DISABLED; - desc->handler->shutdown(irq); - } - spin_unlock_irqrestore(&desc->lock,flags); - -#ifdef CONFIG_SMP - /* Wait to make sure it's not being used on another CPU */ - while (desc->status & IRQ_INPROGRESS) { - barrier(); - cpu_relax(); - } -#endif - kfree(action); - return; - } - printk("Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&desc->lock,flags); - return; - } + desc->action = NULL; + desc->depth = 1; + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + spin_unlock_irqrestore(&desc->lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + do { smp_mb(); } while ( irq_desc[irq].status & IRQ_INPROGRESS ); } -int setup_irq(unsigned int irq, struct irqaction * new) +int setup_irq(unsigned int irq, struct irqaction *new) { - int shared = 0; + irq_desc_t *desc = &irq_desc[irq]; unsigned long flags; - struct irqaction *old, **p; - irq_desc_t *desc = irq_desc + irq; - - /* - * The following block of code has to be executed atomically - */ + spin_lock_irqsave(&desc->lock,flags); - if ( desc->status & IRQ_GUEST ) + if ( desc->action != NULL ) { spin_unlock_irqrestore(&desc->lock,flags); return -EBUSY; } - p = &desc->action; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&desc->lock,flags); - return -EBUSY; - } - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - - *p = new; - - if (!shared) { - desc->depth = 0; - desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); - desc->handler->startup(irq); - } + desc->action = new; + desc->depth = 0; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); spin_unlock_irqrestore(&desc->lock,flags); @@ -536,7 +176,6 @@ int setup_irq(unsigned int irq, struct irqaction * new) } - /* * HANDLING OF GUEST-BOUND PHYSICAL IRQS */ @@ -551,10 +190,10 @@ typedef struct { static void __do_IRQ_guest(int irq) { - irq_desc_t *desc = &irq_desc[irq]; + irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action = (irq_guest_action_t *)desc->action; struct task_struct *p; - int i; + int i; for ( i = 0; i < action->nr_guests; i++ ) { @@ -567,9 +206,9 @@ static void __do_IRQ_guest(int irq) int pirq_guest_unmask(struct task_struct *p) { - irq_desc_t *desc; - int i, j, pirq; - u32 m; + irq_desc_t *desc; + int i, j, pirq; + u32 m; shared_info_t *s = p->shared_info; for ( i = 0; i < 2; i++ ) @@ -594,10 +233,10 @@ int pirq_guest_unmask(struct task_struct *p) int pirq_guest_bind(struct task_struct *p, int irq, int will_share) { - unsigned long flags; - irq_desc_t *desc = &irq_desc[irq]; + irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action; - int rc = 0; + unsigned long flags; + int rc = 0; if ( !IS_CAPABLE_PHYSDEV(p) ) return -EPERM; @@ -630,7 +269,7 @@ int pirq_guest_bind(struct task_struct *p, int irq, int will_share) desc->depth = 0; desc->status |= IRQ_GUEST; - desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); + desc->status &= ~IRQ_DISABLED; desc->handler->startup(irq); /* Attempt to bind the interrupt target to the correct CPU. */ @@ -662,10 +301,10 @@ int pirq_guest_bind(struct task_struct *p, int irq, int will_share) int pirq_guest_unbind(struct task_struct *p, int irq) { - unsigned long flags; - irq_desc_t *desc = &irq_desc[irq]; + irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action; - int i; + unsigned long flags; + int i; spin_lock_irqsave(&desc->lock, flags); @@ -679,6 +318,7 @@ int pirq_guest_unbind(struct task_struct *p, int irq) { desc->action = NULL; kfree(action); + desc->depth = 1; desc->status |= IRQ_DISABLED; desc->status &= ~IRQ_GUEST; desc->handler->shutdown(irq); @@ -695,3 +335,26 @@ int pirq_guest_unbind(struct task_struct *p, int irq) spin_unlock_irqrestore(&desc->lock, flags); return 0; } + +int pirq_guest_bindable(int irq, int will_share) +{ + irq_desc_t *desc = &irq_desc[irq]; + irq_guest_action_t *action; + unsigned long flags; + int okay; + + spin_lock_irqsave(&desc->lock, flags); + + action = (irq_guest_action_t *)desc->action; + + /* + * To be bindable the IRQ must either be not currently bound (1), or + * it must be shareable (2) and not at its share limit (3). + */ + okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */ + (action->shareable && will_share && /* 2 */ + (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */ + + spin_unlock_irqrestore(&desc->lock, flags); + return okay; +} diff --git a/xen/arch/x86/pci-irq.c b/xen/arch/x86/pci-irq.c index 0a6b84c9ba..a99bca1617 100644 --- a/xen/arch/x86/pci-irq.c +++ b/xen/arch/x86/pci-irq.c @@ -903,10 +903,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) if (!(mask & (1 << i))) continue; if (pirq_penalty[i] < pirq_penalty[newirq] && - !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) { - free_irq(i, dev); + pirq_guest_bindable(i,1)) newirq = i; - } } } DBG(" -> newirq=%d", newirq); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index ba95367129..716d25800e 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -300,8 +300,8 @@ unsigned long pci_mem_start = 0x10000000; void __init start_of_day(void) { - extern void trap_init(void); extern void init_IRQ(void); + extern void trap_init(void); extern void time_init(void); extern void ac_timer_init(void); extern void initialize_keytable(); @@ -350,8 +350,8 @@ void __init start_of_day(void) get_smp_config(); #endif scheduler_init(); - trap_init(); init_IRQ(); /* installs simple interrupt wrappers. Starts HZ clock. */ + trap_init(); time_init(); /* installs software handler for HZ clock. */ softirq_init(); init_apic_mappings(); /* make APICs addressable in our pagetables. */ diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 092bb78765..4cfc992b82 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -54,7 +54,7 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { u64 full_tsc; - write_lock(&time_lock); + write_lock_irq(&time_lock); #ifdef CONFIG_X86_IO_APIC if ( timer_ack ) @@ -89,15 +89,14 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Updates system time (nanoseconds since boot). */ stime_irq += MILLISECS(1000/HZ); - write_unlock(&time_lock); + write_unlock_irq(&time_lock); /* Rough hack to allow accurate timers to sort-of-work with no APIC. */ if ( do_timer_lists_from_pit ) __cpu_raise_softirq(smp_processor_id(), AC_TIMER_SOFTIRQ); } -static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, - "timer", NULL, NULL}; +static struct irqaction irq0 = { timer_interrupt, "timer", NULL}; /* ------ Calibrate the TSC ------- * Return processor ticks per second / CALIBRATE_FRAC. diff --git a/xen/drivers/char/keyboard.c b/xen/drivers/char/keyboard.c index e736aa737f..7e4391351e 100644 --- a/xen/drivers/char/keyboard.c +++ b/xen/drivers/char/keyboard.c @@ -13,6 +13,7 @@ #include #include #include +#include /* Hash-defines torn from and */ @@ -241,23 +242,13 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) } +static struct irqaction keyb = { keyboard_interrupt, "Keyboard", NULL }; +static struct irqaction aux = { keyboard_interrupt, "PS/2 Mouse", NULL }; void initialize_keyboard() { spin_lock_init(&kbd_lock); - - if( request_irq(KEYBOARD_IRQ, keyboard_interrupt, - SA_NOPROFILE, "keyboard", NULL)) - { - printk("initialize_keyboard: failed to alloc IRQ %d\n", KEYBOARD_IRQ); - return; - } - - if ( request_irq(AUX_IRQ, keyboard_interrupt, - SA_NOPROFILE, "PS/2 Mouse", NULL)) - { - printk("initialize_keyboard: failed to alloc IRQ %d\n", AUX_IRQ); - return; - } + (void)setup_irq(KEYBOARD_IRQ, &keyb); + (void)setup_irq(AUX_IRQ, &aux); } diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 8e6cd462b8..499f852fda 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -73,11 +74,12 @@ #define RXBUFSZ 32 #define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) typedef struct { - int baud, data_bits, parity, stop_bits, io_base, irq; - serial_rx_fn rx_lo, rx_hi, rx; - spinlock_t lock; - unsigned char rxbuf[RXBUFSZ]; - unsigned int rxbufp, rxbufc; + int baud, data_bits, parity, stop_bits, io_base, irq; + serial_rx_fn rx_lo, rx_hi, rx; + spinlock_t lock; + unsigned char rxbuf[RXBUFSZ]; + unsigned int rxbufp, rxbufc; + struct irqaction irqaction; } uart_t; static uart_t com[2] = { @@ -249,12 +251,10 @@ static void uart_config_stage2(uart_t *uart) if ( !UART_ENABLED(uart) ) return; - rc = request_irq(uart->irq, - serial_interrupt, - SA_NOPROFILE, - "serial", - uart); - if ( rc != 0 ) + uart->irqaction.handler = serial_interrupt; + uart->irqaction.name = "serial"; + uart->irqaction.dev_id = uart; + if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 ) printk("ERROR: Failed to allocate serial IRQ %d\n", uart->irq); /* For sanity, clear the receive FIFO. */ diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index 2c7c67a0da..14d72d9eba 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -6,14 +6,6 @@ #include #include -#define SA_INTERRUPT 0x20000000 -#define SA_SHIRQ 0x04000000 -#define SA_NOPROFILE 0x02000000 - -#define SA_SAMPLE_RANDOM 0 /* Linux driver compatibility */ - -#define TIMER_IRQ 0 - extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); @@ -34,12 +26,6 @@ extern void enable_irq(unsigned int); /* * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - * - * some of the following vectors are 'rare', they are merged - * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. - * TLB, reschedule and local APIC vectors are performance-critical. - * - * Vectors 0xf0-0xfa are free (reserved for future Linux use). */ #define SPURIOUS_APIC_VECTOR 0xff #define ERROR_APIC_VECTOR 0xfe @@ -186,7 +172,7 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "jmp common_interrupt"); extern unsigned long prof_cpu_mask; -extern unsigned int * prof_buffer; +extern unsigned int *prof_buffer; extern unsigned long prof_len; extern unsigned long prof_shift; diff --git a/xen/include/xen/interrupt.h b/xen/include/xen/interrupt.h index 73545a75f8..193c8c394b 100644 --- a/xen/include/xen/interrupt.h +++ b/xen/include/xen/interrupt.h @@ -12,11 +12,8 @@ struct irqaction { void (*handler)(int, void *, struct pt_regs *); - unsigned long flags; - unsigned long mask; const char *name; void *dev_id; - struct irqaction *next; }; #include diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 34f54862bd..2513c59e60 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -12,9 +12,7 @@ #define IRQ_DISABLED 2 /* IRQ disabled - do not enter! */ #define IRQ_PENDING 4 /* IRQ pending - replay on enable */ #define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ -#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ -#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ -#define IRQ_GUEST 64 /* IRQ is handled by guest OS(es) */ +#define IRQ_GUEST 16 /* IRQ is handled by guest OS(es) */ /* * Interrupt controller descriptor. This is all we need @@ -53,6 +51,7 @@ typedef struct { extern irq_desc_t irq_desc[NR_IRQS]; extern int setup_irq(unsigned int, struct irqaction *); +extern void free_irq(unsigned int); extern hw_irq_controller no_irq_type; extern void no_action(int cpl, void *dev_id, struct pt_regs *regs); @@ -61,5 +60,6 @@ struct task_struct; extern int pirq_guest_unmask(struct task_struct *p); extern int pirq_guest_bind(struct task_struct *p, int irq, int will_share); extern int pirq_guest_unbind(struct task_struct *p, int irq); +extern int pirq_guest_bindable(int irq, int will_share); #endif /* __XEN_IRQ_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 1eb0aa8bda..c0902b97d7 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -242,12 +242,6 @@ void new_thread(struct task_struct *p, unsigned long start_stack, unsigned long start_info); -/* Linux puts these here for some reason! */ -extern int request_irq(unsigned int, - void (*handler)(int, void *, struct pt_regs *), - unsigned long, const char *, void *); -extern void free_irq(unsigned int, void *); - extern unsigned long wait_init_idle; #define init_idle() clear_bit(smp_processor_id(), &wait_init_idle); -- 2.30.2